package com.example.demo.demos.broadcast.socket;

import com.example.demo.demos.pojo.Student;
import com.example.demo.demos.pojo.User;

import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class Server {
    private ServerSocket serverSocket;
    private List<PrintWriter> allOut = new CopyOnWriteArrayList<>();

    // 存储当前广播的MD5哈希值
    private String currentBroadcastMD5;
    // 存储客户端响应状态: <客户端IP, 是否已响应>
    private final Map<String, Boolean> clientResponses = new ConcurrentHashMap<>();

    public Server() {
        try {
            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动成功!");

            // 启动UDP广播线程
            new Thread(new BroadcastThread()).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            System.out.println("等待客户端连接...");
            while (true) {
                Socket socket = serverSocket.accept();
                try {
                    // 直接在连接时获取IP地址并打印
                    String host = socket.getInetAddress().getHostAddress();
                    System.out.println("[" + host + "]已连接!");
                    new Thread(new ClientHandler(socket, host)).start();
                } catch (Exception e) {
                    System.out.println("客户端连接异常!");
                }
            }
        } catch (Exception e) {
            System.out.println("服务端异常!");
        }
    }

    public static void main(String[] args) {
        Server server = new Server();
        server.start();
    }

    // 计算字节数组的MD5哈希值
    private String calculateMD5(byte[] data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(data);
            StringBuilder hexString = new StringBuilder();
            for (byte b : digest) {
                hexString.append(String.format("%02x", b));
            }
            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5算法不可用", e);
        }
    }

    // UDP广播线程
    private class BroadcastThread implements Runnable {
        @Override
        public void run() {
            try (DatagramSocket udpSocket = new DatagramSocket()) {
                // 获取主网络接口
                NetworkInterface primaryInterface = getPrimaryNetworkInterface();

                while (true) {
                    try {
                        // 创建广播对象（这里用Map模拟任意对象）
//                        Map<String, Object> broadcastObj = new HashMap<>();
//                        broadcastObj.put("type", "BROADCAST");
                        List<User> users = new ArrayList<>();
                        List<Student> s1 = new ArrayList<>();
                        s1.add(new Student("1",1));
                        s1.add(new Student("2",2));
                        s1.add(new Student("3",3));
                        List<Student> s2 = new ArrayList<>();
                        s2.add(new Student("1",1));
                        s2.add(new Student("2",2));
                        s2.add(new Student("3",3));
                        List<Student> s3 = new ArrayList<>();
                        s3.add(new Student("1",1));
                        s3.add(new Student("2",2));
                        s3.add(new Student("3",3));
                        users.add(new User("张三","1", s1));
                        users.add(new User("李四","2", s2));
                        users.add(new User("王五","3", s3));
//                        broadcastObj.put("content", users);

                        // 序列化对象
                        ByteArrayOutputStream bos = new ByteArrayOutputStream();
                        ObjectOutputStream oos = new ObjectOutputStream(bos);
                        oos.writeObject(users);
                        oos.flush();
                        byte[] buffer = bos.toByteArray();

                        // 计算序列化数据的MD5
                        String md5Hash = calculateMD5(buffer);
                        currentBroadcastMD5 = md5Hash;

                        // 清空之前的响应记录
                        clientResponses.clear();
                        System.out.println("发送新广播对象: " + users.toString());
                        System.out.println("广播MD5: " + md5Hash);

                        // 只使用主网络接口的广播地址
                        if (primaryInterface != null) {
                            for (InterfaceAddress interfaceAddress : primaryInterface.getInterfaceAddresses()) {
                                InetAddress broadcast = interfaceAddress.getBroadcast();
                                if (broadcast == null) continue;

                                // 确保数据包大小在安全范围内
                                if (buffer.length > 1400) {
                                    System.err.println("警告: 广播消息过长 (" + buffer.length + " 字节)");
                                }

                                DatagramPacket packet = new DatagramPacket(
                                        buffer,
                                        buffer.length,
                                        broadcast,
                                        8089
                                );
                                udpSocket.send(packet);
                                System.out.println("已发送广播到: " + broadcast);
                                break; // 只需发送一次
                            }
                        } else {
                            System.err.println("未找到有效的物理网络接口");
                        }

                        Thread.sleep(10000); // 每10秒广播一次
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        break;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        // 获取主网络接口（物理接口）
        private NetworkInterface getPrimaryNetworkInterface() {
            try {
                Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
                while (interfaces.hasMoreElements()) {
                    NetworkInterface networkInterface = interfaces.nextElement();

                    // 跳过回环、虚拟和未启用的接口
                    if (networkInterface.isLoopback() ||
                            !networkInterface.isUp() ||
                            networkInterface.getName().startsWith("veth") ||
                            networkInterface.getName().startsWith("docker") ||
                            networkInterface.getName().startsWith("br-") ||
                            networkInterface.getName().startsWith("virbr") ||
                            networkInterface.getDisplayName().toLowerCase().contains("virtual")) {
                        continue;
                    }

                    // 检查是否有IPv4地址
                    boolean hasIPv4 = false;
                    for (InterfaceAddress addr : networkInterface.getInterfaceAddresses()) {
                        if (addr.getAddress() instanceof Inet4Address) {
                            hasIPv4 = true;
                            break;
                        }
                    }

                    if (hasIPv4) {
                        return networkInterface;
                    }
                }
            } catch (SocketException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    private class ClientHandler implements Runnable {
        private Socket socket;
        private String host; // 存储客户端的IP地址

        public ClientHandler(Socket socket, String host) {
            this.socket = socket;
            this.host = host; // 使用传入的host参数
        }

        @Override
        public void run() {
            PrintWriter pw = null;
            BufferedReader br = null;
            try {
                // 接收消息
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
                br = new BufferedReader(isr);

                // 发送消息
                OutputStream out = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
                BufferedWriter bw = new BufferedWriter(osw);
                pw = new PrintWriter(bw, true);
                allOut.add(pw);

                String clientMsg;
                while ((clientMsg = br.readLine()) != null) {
                    if ("exit".equals(clientMsg)) {
                        System.out.println("[" + host + "]已断开连接!");
                        break;
                    }

                    // 检查是否是广播回应消息
                    if (clientMsg.startsWith("BROADCAST_MD5:")) {
                        String clientMD5 = clientMsg.substring("BROADCAST_MD5:".length());

                        // 验证客户端响应的MD5
                        if (currentBroadcastMD5 != null && currentBroadcastMD5.equals(clientMD5)) {
                            // 检查此IP是否已响应过
                            synchronized (clientResponses) {
                                if (!clientResponses.containsKey(host)) {
                                    // 标记此IP已响应
                                    clientResponses.put(host, true);

                                    // 打印当前响应数量
                                    int responseCount = clientResponses.size();
                                    System.out.println("收到来自[" + host + "]的有效广播回应");
                                    System.out.println("MD5验证成功: " + clientMD5);
                                    System.out.println("当前已收到 " + responseCount + " 个客户端的回应");
                                } else {
                                    System.out.println("收到来自[" + host + "]的重复响应（已记录）");
                                }
                            }
                        } else {
                            System.out.println("收到无效MD5的回应: " + clientMD5);
                            System.out.println("预期MD5: " + currentBroadcastMD5);
                        }
                    } else {
                        // 普通聊天消息
                        System.out.println("[" + host + "]:");
                        System.out.println("\t" + clientMsg);
                        for (PrintWriter o : allOut) {
                            o.println("[" + host + "]:" + clientMsg);
                        }
                    }
                }
            } catch (SocketException e) {
                // 使用安全的host变量
                System.out.println("[" + (host != null ? host : "未知客户端") + "]连接意外断开");
            } catch (IOException e) {
                // 使用安全的host变量
                System.out.println("[" + (host != null ? host : "未知客户端") + "]已断开连接!");
            } finally {
                // 移除输出流
                if (pw != null) {
                    allOut.remove(pw);
                }

                // 安全关闭资源
                if (br != null) {
                    try {
                        br.close();
                    } catch (IOException e) {
                        System.out.println("关闭BufferedReader时出错: " + e.getMessage());
                    }
                }

                if (pw != null) {
                    pw.close();
                }

                if (socket != null && !socket.isClosed()) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        System.out.println("关闭Socket时出错: " + e.getMessage());
                    }
                }

                System.out.println("[" + (host != null ? host : "未知客户端") + "]资源已清理");
            }
        }
    }
}